﻿using System;
using System.Collections.Generic;
using System.Text;
using PW.Mini.SlepowronskiJ.Siec.Budowa;

namespace PW.Mini.SlepowronskiJ.Siec.Algorytmy
{
    [Serializable]
    public abstract class  RPROPAbstractAlgorytmUczenia : AlgorytmUczenia
    {
        protected double[][][] wspolczynnikUczenia;
        protected double[][][] prevDelta;

        protected const double maxWspolczynnikUczenia = 50.0d;
        //todo zmienilem z 10e-6 na 10e-8
        protected const double minWspolczynnikUczenia = 10e-6;
        protected const double a = 1.2d;
        protected const double b = 0.5d;
        protected const double zero = 0.00000000000000001d;

        #region konstruktor

        /// <summary>
        /// tworzy nowy obiekt klasy algorytmu  
        /// </summary>
        public RPROPAbstractAlgorytmUczenia()
            : base()
        {}

        /// <summary>
        /// tworzy nowy obiekt klasy algorytmu  dla
        /// sieci neuronowej
        /// </summary>
        /// <param name="siecNeuronowa">siec neuronowa do uczenia</param>
        public RPROPAbstractAlgorytmUczenia(SiecNeuronowa siecNeuronowa)
            : base(siecNeuronowa)
        {}

        #endregion

        protected double wyliczWspolczynnikUczenia(int nrWarstwy, int nrNeuronu, int nrWagi, double delta, double poprzedniaZmiana)
        {
            double zmianaGradientu = delta * prevDelta[nrWarstwy][nrNeuronu][nrWagi];
            int znak = 0;
            if (Math.Abs(zmianaGradientu) < zero)
                znak = 0;
            else if (zmianaGradientu > 0)
                znak = 1;
            else if (zmianaGradientu < 0)
                znak = -1;

            if (znak > 0)
            {
                wspolczynnikUczenia[nrWarstwy][nrNeuronu][nrWagi] = Math.Min(
                    a * wspolczynnikUczenia[nrWarstwy][nrNeuronu][nrWagi], maxWspolczynnikUczenia);
                prevDelta[nrWarstwy][nrNeuronu][nrWagi] = delta;
            }
            else if (znak < 0)
            {
                wspolczynnikUczenia[nrWarstwy][nrNeuronu][nrWagi] = Math.Max(
                    b * wspolczynnikUczenia[nrWarstwy][nrNeuronu][nrWagi], minWspolczynnikUczenia);
                prevDelta[nrWarstwy][nrNeuronu][nrWagi] = 0;
                //todo zmiana
                //return -this.monitor.Moment * poprzedniaZmiana;
            }
            else
                prevDelta[nrWarstwy][nrNeuronu][nrWagi] = delta;
            if (delta > 0)
                znak = -1;
            else if (delta < 0)
                znak = 1;
            
            return wspolczynnikUczenia[nrWarstwy][nrNeuronu][nrWagi] * znak;
        }
    }
}
